import os
import json
import csv
import io
import logging
from pathlib import Path
from typing import Dict, Any, Optional, List

# 文件解析相关库 - 优雅处理缺失的依赖
try:
    import PyPDF2
    HAS_PDF = True
except ImportError:
    HAS_PDF = False
    print("警告: PyPDF2 未安装，PDF解析功能不可用")

try:
    from docx import Document
    HAS_DOCX = True
except ImportError:
    HAS_DOCX = False
    print("警告: python-docx 未安装，Word文档解析功能不可用")

try:
    import openpyxl
    import pandas as pd
    HAS_EXCEL = True
except ImportError:
    HAS_EXCEL = False
    print("警告: openpyxl/pandas 未安装，Excel解析功能不可用")

try:
    from PIL import Image
    import pytesseract
    HAS_OCR = True
except ImportError:
    HAS_OCR = False
    print("警告: Pillow/pytesseract 未安装，图像OCR功能不可用")

try:
    import magic
    HAS_MAGIC = True
except ImportError:
    HAS_MAGIC = False
    print("警告: python-magic 未安装，文件类型检测功能受限")

try:
    import chardet
    HAS_CHARDET = True
except ImportError:
    HAS_CHARDET = False
    print("警告: chardet 未安装，字符编码检测功能不可用")


class FileParser:
    """文件解析器，支持多种文件格式转换为文本"""
    
    def __init__(self):
        self.logger = logging.getLogger(__name__)
        
        # 支持的文件类型映射
        self.parsers = {
            '.txt': self._parse_text,
            '.md': self._parse_text,
            '.py': self._parse_text,
            '.js': self._parse_text,
            '.java': self._parse_text,
            '.cpp': self._parse_text,
            '.c': self._parse_text,
            '.html': self._parse_text,
            '.css': self._parse_text,
            '.json': self._parse_text,
            '.xml': self._parse_text,
            '.csv': self._parse_csv,
            '.pdf': self._parse_pdf,
            '.docx': self._parse_docx,
            '.doc': self._parse_docx,
            '.xlsx': self._parse_excel,
            '.xls': self._parse_excel,
            '.jpg': self._parse_image,
            '.jpeg': self._parse_image,
            '.png': self._parse_image,
            '.gif': self._parse_image,
            '.bmp': self._parse_image,
        }
    
    def parse_file(self, file_path: str, original_name: str) -> Dict[str, Any]:
        """
        解析文件内容
        
        Args:
            file_path: 文件路径
            original_name: 原始文件名
            
        Returns:
            Dict包含: content(文本内容), file_type(文件类型), success(是否成功), error(错误信息)
        """
        try:
            # 获取文件扩展名
            file_ext = os.path.splitext(original_name.lower())[1]
            
            # 检查文件是否存在
            if not os.path.exists(file_path):
                return {
                    'content': '',
                    'file_type': file_ext,
                    'success': False,
                    'error': '文件不存在'
                }
            
            # 获取文件大小
            file_size = os.path.getsize(file_path)
            if file_size > 50 * 1024 * 1024:  # 50MB限制
                return {
                    'content': f'文件过大 ({self._format_file_size(file_size)})，无法解析',
                    'file_type': file_ext,
                    'success': False,
                    'error': '文件过大'
                }
            
            # 选择解析器
            parser = self.parsers.get(file_ext, self._parse_unknown)
            
            # 解析文件
            content = parser(file_path, original_name)
            
            return {
                'content': content,
                'file_type': file_ext,
                'success': True,
                'error': None
            }
            
        except Exception as e:
            self.logger.error(f"解析文件失败 {original_name}: {e}")
            return {
                'content': f'解析失败: {str(e)}',
                'file_type': file_ext if 'file_ext' in locals() else 'unknown',
                'success': False,
                'error': str(e)
            }
    
    def _parse_text(self, file_path: str, original_name: str) -> str:
        """解析文本文件"""
        try:
            # 尝试检测编码
            with open(file_path, 'rb') as f:
                raw_data = f.read()
                
                if HAS_CHARDET:
                    encoding_result = chardet.detect(raw_data)
                    encoding = encoding_result.get('encoding', 'utf-8')
                else:
                    encoding = 'utf-8'
            
            # 读取文件内容
            try:
                with open(file_path, 'r', encoding=encoding) as f:
                    content = f.read()
                return content
            except UnicodeDecodeError:
                # 如果检测的编码失败，尝试常见编码
                for enc in ['utf-8', 'gbk', 'gb2312', 'latin-1']:
                    try:
                        with open(file_path, 'r', encoding=enc) as f:
                            content = f.read()
                        return content
                    except UnicodeDecodeError:
                        continue
                
                return "❌ 无法解码文件内容，可能是二进制文件"
                
        except Exception as e:
            return f"❌ 读取文本文件失败: {str(e)}"
    
    def _parse_csv(self, file_path: str, original_name: str) -> str:
        """解析CSV文件"""
        try:
            if not HAS_EXCEL:
                return self._parse_text(file_path, original_name)
            
            # 尝试不同编码读取CSV
            for encoding in ['utf-8', 'gbk', 'gb2312']:
                try:
                    df = pd.read_csv(file_path, encoding=encoding)
                    # 限制显示行数
                    if len(df) > 100:
                        preview_df = df.head(100)
                        content = f"CSV文件预览 (显示前100行，共{len(df)}行):\n\n"
                        content += preview_df.to_string(index=False)
                        content += f"\n\n... 还有 {len(df) - 100} 行数据"
                    else:
                        content = f"CSV文件内容 (共{len(df)}行):\n\n"
                        content += df.to_string(index=False)
                    return content
                except UnicodeDecodeError:
                    continue
                except Exception as e:
                    self.logger.warning(f"pandas读取CSV失败，尝试文本模式: {e}")
                    break
            
            # 如果pandas失败，回退到文本模式
            return self._parse_text(file_path, original_name)
            
        except Exception as e:
            return f"❌ 解析CSV文件失败: {str(e)}"
    
    def _parse_pdf(self, file_path: str, original_name: str) -> str:
        """解析PDF文件"""
        try:
            if not HAS_PDF:
                return "❌ PDF解析库未安装，无法解析PDF文件"
            
            with open(file_path, 'rb') as file:
                pdf_reader = PyPDF2.PdfReader(file)
                text_content = []
                
                # 限制页数
                max_pages = min(50, len(pdf_reader.pages))
                
                for page_num in range(max_pages):
                    page = pdf_reader.pages[page_num]
                    text = page.extract_text()
                    if text.strip():
                        text_content.append(f"=== 第 {page_num + 1} 页 ===\n{text}")
                
                if not text_content:
                    return "❌ PDF文件中未找到可提取的文本内容"
                
                content = "\n\n".join(text_content)
                if len(pdf_reader.pages) > max_pages:
                    content += f"\n\n... PDF还有 {len(pdf_reader.pages) - max_pages} 页未显示"
                
                return content
                
        except Exception as e:
            return f"❌ 解析PDF文件失败: {str(e)}"
    
    def _parse_docx(self, file_path: str, original_name: str) -> str:
        """解析Word文档"""
        try:
            if not HAS_DOCX:
                return "❌ Word解析库未安装，无法解析Word文档"
            
            doc = Document(file_path)
            text_content = []
            
            # 提取段落文本
            for paragraph in doc.paragraphs:
                if paragraph.text.strip():
                    text_content.append(paragraph.text)
            
            # 提取表格文本
            for table in doc.tables:
                table_text = []
                for row in table.rows:
                    row_text = []
                    for cell in row.cells:
                        row_text.append(cell.text.strip())
                    table_text.append(" | ".join(row_text))
                
                if table_text:
                    text_content.append("\n表格内容:\n" + "\n".join(table_text))
            
            if not text_content:
                return "❌ Word文档中未找到文本内容"
            
            return "\n\n".join(text_content)
            
        except Exception as e:
            return f"❌ 解析Word文档失败: {str(e)}"
    
    def _parse_excel(self, file_path: str, original_name: str) -> str:
        """解析Excel文件"""
        try:
            if not HAS_EXCEL:
                return "❌ Excel解析库未安装，无法解析Excel文件"
            
            # 使用pandas读取Excel
            excel_file = pd.ExcelFile(file_path)
            text_content = []
            
            # 限制工作表数量
            max_sheets = min(10, len(excel_file.sheet_names))
            
            for sheet_name in excel_file.sheet_names[:max_sheets]:
                df = pd.read_excel(file_path, sheet_name=sheet_name)
                
                if not df.empty:
                    # 限制显示行数
                    if len(df) > 50:
                        preview_df = df.head(50)
                        sheet_content = f"工作表 '{sheet_name}' (显示前50行，共{len(df)}行):\n"
                        sheet_content += preview_df.to_string(index=False)
                        sheet_content += f"\n... 还有 {len(df) - 50} 行数据"
                    else:
                        sheet_content = f"工作表 '{sheet_name}' (共{len(df)}行):\n"
                        sheet_content += df.to_string(index=False)
                    
                    text_content.append(sheet_content)
            
            if not text_content:
                return "❌ Excel文件中未找到数据"
            
            content = "\n\n".join(text_content)
            if len(excel_file.sheet_names) > max_sheets:
                content += f"\n\n... 还有 {len(excel_file.sheet_names) - max_sheets} 个工作表未显示"
            
            return content
            
        except Exception as e:
            return f"❌ 解析Excel文件失败: {str(e)}"
    
    def _parse_image(self, file_path: str, original_name: str) -> str:
        """解析图片文件（提取基本信息）"""
        try:
            if not HAS_OCR:
                return f"📷 图片文件: {original_name} (需要安装Pillow库才能获取详细信息)"
            
            with Image.open(file_path) as img:
                # 获取图片基本信息
                width, height = img.size
                mode = img.mode
                format_name = img.format
                
                # 计算文件大小
                file_size = os.path.getsize(file_path)
                
                info = f"""📷 图片文件信息:
文件名: {original_name}
格式: {format_name}
尺寸: {width} x {height} 像素
颜色模式: {mode}
文件大小: {self._format_file_size(file_size)}

注意: 这是一个图片文件，无法提取文本内容。如果图片中包含文字，建议使用OCR工具进行文字识别。"""
                
                return info
                
        except Exception as e:
            return f"📷 图片文件: {original_name} (解析失败: {str(e)})"
    
    def _parse_unknown(self, file_path: str, original_name: str) -> str:
        """处理未知文件类型"""
        try:
            file_size = os.path.getsize(file_path)
            
            # 尝试检测文件类型
            file_type = "未知"
            try:
                if magic:
                    file_type = magic.from_file(file_path)
            except:
                pass
            
            # 尝试作为文本文件读取
            try:
                with open(file_path, 'rb') as f:
                    sample = f.read(1024)  # 读取前1KB
                
                # 检测是否为文本文件
                if self._is_text_file(sample):
                    return self._parse_text(file_path, original_name)
            except:
                pass
            
            return f"""📄 未知文件类型:
文件名: {original_name}
文件类型: {file_type}
文件大小: {self._format_file_size(file_size)}

该文件类型暂不支持内容解析。支持的文件类型包括:
- 文本文件: .txt, .md, .py, .js, .java, .cpp, .c, .html, .css, .json, .xml
- 表格文件: .csv, .xlsx, .xls
- 文档文件: .pdf, .docx, .doc
- 图片文件: .jpg, .jpeg, .png, .gif, .bmp"""
            
        except Exception as e:
            return f"❌ 处理未知文件失败: {str(e)}"
    
    def _is_text_file(self, sample: bytes) -> bool:
        """检测是否为文本文件"""
        try:
            # 检查是否包含null字节（二进制文件的特征）
            if b'\x00' in sample:
                return False
            
            # 尝试解码为文本
            sample.decode('utf-8')
            return True
        except UnicodeDecodeError:
            try:
                sample.decode('gbk')
                return True
            except UnicodeDecodeError:
                return False
    
    def _format_file_size(self, size_bytes: int) -> str:
        """格式化文件大小"""
        if size_bytes < 1024:
            return f"{size_bytes} B"
        elif size_bytes < 1024 * 1024:
            return f"{size_bytes / 1024:.1f} KB"
        else:
            return f"{size_bytes / 1024 / 1024:.1f} MB"
    
    def get_supported_extensions(self) -> list:
        """获取支持的文件扩展名列表"""
        return list(self.parsers.keys())
    
    def is_supported(self, filename: str) -> bool:
        """检查文件是否支持解析"""
        ext = os.path.splitext(filename.lower())[1]
        return ext in self.parsers